package org.jee.rpc;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

/**
 * 描述:RPC服务发布者 Created by bysocket on 16/2/28.
 */
public class RpcExporter {
	// 创建线程池
	static Executor executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

	public static void exporter(String hostName, int port) throws IOException {
		ServerSocket serverSocket = new ServerSocket();
		serverSocket.bind(new InetSocketAddress(hostName, port));
		try {
			while (true) {
				/**
				 * 监听Client的TCP连接,将其封装成Task,由线程池执行.
				 */
				executor.execute(new ExporterTask(serverSocket.accept()));
			}
		} finally {
			serverSocket.close();
		}
	}

	/**
	 * 线程Task: 1. 将客户端发送的二进制流反序列化成对象,反射调用服务实现者,获取执行结果 2.
	 * 将执行结果对象反序列化,通过Socket发送给客户端 3. 远程服务调用完成之后,释放Socket等连接资源,防止句柄泄漏
	 */
	private static class ExporterTask implements Runnable {
		Socket client = null;

		public ExporterTask(Socket accept) {
			this.client = accept;
		}

		@Override
		public void run() {
			ObjectInputStream input = null;
			ObjectOutputStream output = null;
			try {
				// 对象输入流
				input = new ObjectInputStream(client.getInputStream());

				// 获取接口名
				String interfaceName = input.readUTF();
				// 获取方法名
				String methodName = input.readUTF();
				// 获取方法的参数数组
				Class<?>[] paramTypes = (Class<?>[]) input.readObject();
				// 获取传入参数对象数组
				Object[] arguments = (Object[]) input.readObject();

				// 获取服务对象类
				Class<?> service = Class.forName(interfaceName);
				// 获取服务方法
				Method method = service.getMethod(methodName, paramTypes);
				// 获取服务方法返回对象
				Object result = method.invoke(service.newInstance(), arguments);

				// 对象输出流
				output = new ObjectOutputStream(client.getOutputStream());
				output.writeObject(result);

			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				// 关闭流的操作
				if (output != null) {
					try {
						output.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}

				if (input != null) {
					try {
						input.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}

				if (client != null) {
					try {
						client.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}
}
